import Base3d from "../base/Base3d";
import * as THREE from "three";
import earth from "../../assets/texture/earth.png"
import earthBlack from "../../assets/texture/earthBlack.png"
import earthEdge from "../../assets/texture/earthEdge.png"
import {bd09towgs84} from "../tool/LngLatHelper";
import LocationHelper from "../tool/LocationHelper";
import waternormal from "../../assets/texture/waternormals2.jpg"
import config from "../config/config";
import wsEvents from "../../components/wsEvents";
import app from "../main/app";
import china from "../geodata/china";
import outLine from "../base/geometryFactory/outLine";

export default class world extends Base3d{
  init() {
    let onlineColor=0x00CAFC
    let offlineColor=0xDD5246
    this.R=config.getConfigByKey("worldR");
    this.outWorldR=config.getConfigByKey("outWorldR")
    this.time=0;
    this.points=[];
    this.server = {};
    super.init();
    this.magicShader=[];
    window.goTo({x:-867.6815205530546,y:-57.72434547142974,z:-557.17727180324},{x:0,y:0,z:0})
    window.flyTo({x:-66.2838883159264,y:171.5149409606977,z:-198.7325682342233},{x:0,y:0,z:0})
    let lngLat=bd09towgs84(117.856505,38.899832);
    let geometry=new THREE.SphereGeometry( this.R, 100, 100 );
    this.earthTexture=new THREE.TextureLoader().load(earth)
    this.earthEdgeTexture=new THREE.TextureLoader().load(earthEdge)
    this.scene.add(new THREE.Mesh(geometry,this.getShader()));
    //this.scene.add(new THREE.Mesh(new THREE.CircleGeometry(170,300,100),new THREE.MeshStandardMaterial({color:0xffffff})))
    let testMesh=new THREE.PlaneBufferGeometry(10,10,10,10);
    this.createWorldEdge();
    this.createChina();
    let points=[
      [117.856505,38.899832],
      [113.842347,22.540979]
    ]
    // points.forEach((item)=>{
    //   let mesh=this.createPoint(0x00CAFC,bd09towgs84(item[0],item[1]))
    //   this.scene.add(mesh)
    // })
    app.register(wsEvents.events.ON_ADD_SERVER, (uniqueId,lng,lat,online)=>{
      let mesh=null
      if (!this.scene.getObjectByName(uniqueId)){
        mesh=this.createPoint(onlineColor,bd09towgs84(lng,lat))
        mesh.name=uniqueId
        this.scene.add(mesh)
      }else {
        mesh=this.scene.getObjectByName(uniqueId)
      }
      if (mesh){
        let color=onlineColor
        if (!online){
          color=offlineColor
        }
        mesh.children[0].children[0].children[0].material.uniforms.uMainColor.value=new THREE.Color(color)
        mesh.children[0].children[0].children[1].material.uniforms.uLineColor.value=new THREE.Color(color)
      }
    })
    app.register(wsEvents.events.ON_WS_RECORD_NODES,(msg)=>{
      for(let key in msg){
        let uniqueId=msg[key].UniqueId
        let i=msg[key]
        i.online=true;
        this.server[uniqueId]=i
        app.trigger(wsEvents.events.ON_ADD_SERVER,uniqueId,i['Location']['lng'],i['Location']['lat'],i.online)
      }
    })
    app.register(wsEvents.events.ON_WS_DISCONNECT,()=>{
      for (let i in this.server){
        let item=this.server[i]
        item.online=false
        app.trigger(wsEvents.events.ON_ADD_SERVER,i,item['Location']['lng'],item['Location']['lat'],item.online)
      }
    })
  }
  createChina(){
    let data = [];
    for (let i of china){
      let itemData = LocationHelper.lglt2xyz(i.lng,i.lat,this.outWorldR-5);
      data.push(itemData)
    }
    this.chinaShader = new THREE.ShaderMaterial({
      side:THREE.DoubleSide,
      transparent:true,
      uniforms: {
        uTime:{
          value:0
        },
        uBaseColor:{
          value:new THREE.Color(0x0070D9)
        },
        uLightColor:{
          value:new THREE.Color(0xCF7BEC)
        },
        PI:{
          value:Math.PI
        }
      },
      vertexShader: `
        varying vec2 vUv;
        void main(){
         vUv=uv;
         gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
      `
      ,
      fragmentShader:`
        varying vec2 vUv;
        uniform float uTime;
        uniform sampler2D uEarthTexture;
        uniform float uAngleSin;
        uniform float PI;
        uniform vec3 uBaseColor;
        uniform vec3 uFogColor;
        uniform vec3 uLightColor;
        float remain(float x,float num){
                return x-floor(x/num)*num;
        }
        float hasColor(vec4 color){
              return ceil((color.x+color.y+color.z)/10.0)*color.w;
        }
        //是否是奇数
        float isSingleNum(float x){
                return ceil(remain(x,2.0));
        }
        float singleIncrease(float x){
              x=remain(x,PI*2.0);
              float sinData=1.0-ceil(step(PI/2.0,remain(x,PI)));//是否使用sin函数
              float cosData=isSingleNum(floor(x/(PI/2.0)));//是否使用cos函数
              return cosData*abs(cos(x))+sinData*abs(sin(x))+0.05;
       }
        void main(){
          float x =singleIncrease(uTime*0.1);
          float height = 0.02;
          // float value = (x-vUv.y)*(vUv.y-x-height);
          float value= step(abs(vUv.y-x),height);
          float lightColorRadio = smoothstep(0.0,height*2.0,(vUv.y+height-x));
          gl_FragColor = (vec4(vec3(uBaseColor),1.0)+0.6*lightColorRadio*vec4(uLightColor,1.0)*value)*value;
          gl_FragColor = vec4(gl_FragColor.xyz,gl_FragColor.w*0.8);
          if(hasColor(gl_FragColor.xyzw)==0.0){
              discard;
          }
        }
      `,
    })
    let mesh = new THREE.Mesh(new outLine().getOutLineGeometry(data,0.5,10),this.chinaShader)
    this.scene.add(mesh)
  }
  createWorldEdge(){
    let geometry=new THREE.CircleGeometry(this.R+15,60);
    let shader=new THREE.ShaderMaterial({
      side:THREE.DoubleSide,
      transparent:true,
      uniforms: {
        uTime:{
          value:0
        },
        uEarthTexture:{
          value:this.earthEdgeTexture
        },
        uFogColor:{
          value:new THREE.Vector3(0.137, 0.231, 0.423)
        },
        uBaseColor:{
          value:new THREE.Color(0x0070D9)
        },
        uAngleSin:{
          value:Math.sin(Math.PI*0.1)
        },
        PI:{
          value:Math.PI
        }
      },
      vertexShader: `
        varying vec2 vUv;
        void main(){
         vUv=uv;
         gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
      `
      ,
      fragmentShader:`
        varying vec2 vUv;
        uniform float uTime;
        uniform sampler2D uEarthTexture;
        uniform float uAngleSin;
        uniform float PI;
        uniform vec3 uBaseColor;
        uniform vec3 uFogColor;
        float remain(float x,float num){
                return x-floor(x/num)*num;
        }
        float hasColor(vec4 color){
              return ceil((color.x+color.y+color.z)/10.0)*color.w;
        }
        //是否是奇数
        float isSingleNum(float x){
                return ceil(remain(x,2.0));
        }
        float singleIncrease(float x){
              x=remain(x,PI*2.0);
              float sinData=1.0-ceil(step(PI/2.0,remain(x,PI)));//是否使用sin函数
              float cosData=isSingleNum(floor(x/(PI/2.0)));//是否使用cos函数
              return cosData*abs(cos(x))+sinData*abs(sin(x))+0.05;
       }
        float IsInAngle(float x,float y){
              float originY = y;
              y = sin(uTime)*ceil(0.5-y)+y+sin(uTime)*(ceil(0.5-y)-1.0);
             // x = sin(uTime)*ceil(0.5-x)+x+sin(uTime)*(ceil(0.5-x)-1.0);
              return ceil(abs(((y-0.5)/0.7071))-uAngleSin)*abs(sin(x+uTime))
              ;
        }
        void main(){
          gl_FragColor=(gl_FragColor.x+gl_FragColor.y+gl_FragColor.z)*vec4(1.0,1.0,1.0,1.0);
          // gl_FragColor = vec4(mix(uFogColor,uBaseColor,clamp((distance(vec2(0.5,0.5),vUv)),0.45,0.5)),1.0);
          //gl_FragColor = vec4(mix(uFogColor,uBaseColor,1.0-(distance(vec2(0.5,0.5),vUv)-0.2)*10.0),1.0);
          gl_FragColor = vec4(uBaseColor,1.0)*(1.0-(distance(vec2(0.5,0.5),vUv)-0.45)*12.0)*hasColor(texture2D(uEarthTexture,vUv));
         gl_FragColor = gl_FragColor*IsInAngle(vUv.x,vUv.y);
          if(hasColor(gl_FragColor.xyzw)==0.0){
              discard;
          }
        }
      `,
    })
    let mesh=new THREE.Mesh(geometry,shader);
    this.edgeShader = shader;
    this.scene.add(mesh)
  }
  createPoint(mainColor,lngLat){
    let pointGeometry=new THREE.OctahedronGeometry(2);
    let mesh = new THREE.Mesh(pointGeometry,this.getPointShader(mainColor))
    let group=new THREE.Group();
    let line=this.getEdgeLine(mesh,mainColor)
    let bottomMesh=new THREE.Mesh(new THREE.CircleGeometry(6,32),this.getBottomShader());
    let pointContainer=new THREE.Group()
    pointContainer.name="pointContainer"
    pointContainer.add(mesh)
    pointContainer.add(line)
    pointContainer.position.setZ(-8)
    this.points.push(pointContainer)
    group.add(pointContainer)
    group.add(bottomMesh)
    //bottomMesh.position.setZ(5)
    //group.position.setZ(-8)
    let waterTexture=(new THREE.TextureLoader()).load(waternormal);
    waterTexture.wrapS=waterTexture.wrapT=THREE.RepeatWrapping
    let container=new THREE.Group()
    container.add(group)
    this.setLocation(container,lngLat)
    return container
  }
  getBottomShader(){
    let magicMaterial= new THREE.ShaderMaterial({
      // depthWrite: true,
      depthTest: true,
      transparent: true,
      // opacity: 0.3,
      side:THREE.DoubleSide,
      uniforms: {
        u_time: {
          'type': "f",
          'value': 0.0,
        },
        PI:{
          value:Math.PI
        },
        startX:{
          value:0.0
        },
        uCircleColor:{
          value:new THREE.Color(0x4CD09A)
        },
        uBaseLightColor:{
          value:new THREE.Color(0x00A84A)
        }
      },
      vertexShader: `
          varying vec2 uVu;
          void main(){
              uVu=uv;
              gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
          }
        `,
      fragmentShader: `
          varying vec2 uVu;
          uniform float u_time;
          uniform float PI;
          uniform float startX;
          uniform sampler2D uTexture;
          uniform vec3 uCircleColor;
          uniform vec3 uBaseLightColor;
          float remain(float x,float num){
                return x-floor(x/num)*num;
          }
          //是否是奇数
          float isSingleNum(float x){
                return ceil(remain(x,2.0));
          }
          float circleMax(float min){
                return step(min,distance(uVu.xy,vec2(0.5,0.5)));
          }
          float circleMin(float max){
                return step(distance(uVu.xy,vec2(0.5,0.5)),max);
          }
          float hasColor(vec3 color){
                return ceil((color.x+color.y+color.z)/10.0);
          }
          float singleIncrease(float x){
              x=remain(x,PI*2.0);
              float sinData=1.0-ceil(step(PI/2.0,remain(x,PI)));//是否使用sin函数
              float cosData=isSingleNum(floor(x/(PI/2.0)));//是否使用cos函数
              return cosData*abs(cos(x))+sinData*abs(sin(x))+0.05;
          }
          float singleSub(float x){
              x=remain(x,PI*2.0);
              float sinData=1.0-ceil(step(PI/2.0,remain(x,PI)));//是否使用sin函数
              float cosData=isSingleNum(floor(x/(PI/2.0)));//是否使用cos函数
              return (1.0-cosData)*abs(cos(x))+(1.0-sinData)*abs(sin(x));
          }
          vec4 getCircleColor(float baseTimeAdd,float width){
                return (vec4(uCircleColor,1.0)+(vec4(1.0,1.0,1.0,1.0))*0.2)*circleMin(singleIncrease((u_time+baseTimeAdd)/4.0)*0.5)*circleMax(singleIncrease((u_time+baseTimeAdd-width)/4.0)*0.5)*(0.8-distance(vec2(uVu),vec2(0.5,0.5)));
          }
          vec4 getCircleColorFixed(float min,float max){
                return (vec4(uCircleColor,1.0))*circleMin(min)*circleMax(max);
          }

          vec4 getLightColor(){
               vec4 lightColor = vec4(uBaseLightColor,0.4-distance(vec2(uVu),vec2(0.5,0.5)));
               lightColor+=hasColor(lightColor.xyz)*vec4(1.0,1.0,1.0,1.0)*(0.4-distance(vec2(uVu),vec2(0.5,0.5)))*0.5;
               return lightColor;
          }
          void main(){
               vec4 color=texture2D(uTexture,uVu.xy)*step(distance(uVu.xy,vec2(0.5,0.5)),startX);
               color=hasColor(color.xyz)*vec4(uCircleColor,1.0)*circleMin((singleSub((u_time)/4.0)))+color;
               gl_FragColor = getCircleColor(PI/4.0,0.1)+getCircleColor(PI/2.0,0.1)+getCircleColor(PI,0.1)+getCircleColor(PI*2.0/4.0,0.1)+getCircleColor(PI*3.0/4.0,0.1)+getCircleColor(PI*4.0/4.0,0.1)+getCircleColor(PI*5.0/4.0,0.1)+getCircleColor(PI*1.5,0.1)
                              +getCircleColor(PI*2.0,0.1)
                              +getLightColor()
               ;
          }
        `,
    });
    this.magicShader.push(magicMaterial)
    return magicMaterial
  }
  getEdgeLine(mesh,color){
    let shader= new THREE.ShaderMaterial({
      side:THREE.DoubleSide,
      uniforms: {
        uTime:{
          value:0
        },
        uLineColor:{
          value:new THREE.Color(color)
        }
      },
      vertexShader: `
        varying vec2 vUv;
        void main(){
         vUv=uv;
         gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
      `
      ,
      fragmentShader:`
        varying vec2 vUv;
        uniform float uTime;
        uniform vec3 uLineColor;
        void main(){
          gl_FragColor=vec4(uLineColor,1.0);
        }
      `,
    })

    const edges = new THREE.EdgesGeometry( mesh.geometry );
    const line = new THREE.LineSegments( edges,shader);
    line.position.set(mesh.position.x,mesh.position.y,mesh.position.z)
    line.scale.set(mesh.scale.x*1.1,mesh.scale.y*1.1,mesh.scale.z*1.1)
    return line
  }
  getPointShader(mainColor){
    let shader= new THREE.ShaderMaterial({
      side:THREE.DoubleSide,
      transparent:true,
      uniforms: {
        uTime:{
          value:0
        },
        uMainColor:{
          value:new THREE.Color(mainColor)
        }
      },
      vertexShader: `
        varying vec2 vUv;
        void main(){
         vUv=uv;
         gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
      `
      ,
      fragmentShader:`
        varying vec2 vUv;
        uniform float uTime;
        uniform vec3 uMainColor;
        void main(){
          gl_FragColor=vec4(uMainColor,vUv.y+0.2);
        }
      `,
    })
    return shader
  }
  getShader(){
    this.shader=new THREE.ShaderMaterial({
      side:THREE.DoubleSide,
      uniforms: {
        uTime:{
          value:0
        },
        mapTexture:{
          value: this.earthTexture
        }
      },
      vertexShader: `
        varying vec2 vUv;
        void main(){
         vUv=uv;
         gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
      `
      ,
      fragmentShader:`
        varying vec2 vUv;
        uniform float uTime;
        uniform sampler2D mapTexture;
        void main(){
          gl_FragColor=texture2D(mapTexture,vUv)-vec4(1.0,1.0,1.0,1.0)*0.35;
        }
      `,
    })
    return this.shader
  }
  setLocation(mesh,lngLat){
    let position=LocationHelper.lglt2xyz(lngLat[0],lngLat[1],this.outWorldR)
    let x=position.x;
    let y=position.y;
    let z=position.z
    let xR=0;
    let yR=0;
    xR=Math.asin(x/this.getLong(x,z,y))
    yR=-Math.asin(y/this.getLong(y,z))
    if (z<0){
      xR=-xR;
      yR=-yR;
    }
    // let zR=(mesh.position.z/this.R)*(Math.PI*0.5)
    mesh.position.set(position.x,position.y,position.z)
    mesh.rotation.set(yR,xR,0.0)
  }
  getLong(...nums){
    let total=0
    nums.forEach((num)=>{
      total+=Math.pow(num,2.0)
    })
    if (total===0){
      return 1
    }
    return Math.sqrt(total)
  }
  animation(){
    this.time+=0.01;
    if(!this.originZ){
      this.originZ={}
    }
    let self=this;
    let points=this.scene.getObjectByName("pointContainer")
    this.points.forEach((item)=>{
      if(!this.originZ[item.uuid]){
        this.originZ[item.uuid]=item.position.z;
      }
      item.position.setZ(this.originZ[item.uuid]+Math.sin(self.time)*5)
      item.rotateZ(0.05)
    })
  }
  render() {
    this.magicShader.forEach((item)=>{
      item.uniforms.u_time.value+=0.02;
    })
    this.edgeShader.uniforms.uTime.value+=0.01;
    this.chinaShader.uniforms.uTime.value+=0.01;
    this.animation();
    super.render();
  }
}
